Development tools and frameworks usually have options to make debugging easier for developers. Although these features are useful during
development, they should never be enabled for applications deployed in production. Debug instructions or error messages can leak detailed information
about the system, like the application’s path or file names.
Ask Yourself Whether
- The code or configuration enabling the application debug features is deployed on production servers or distributed to end users.
- The application runs by default with debug features activated.
There is a risk if you answered yes to any of those questions.
Recommended Secure Coding Practices
Do not enable debugging features on production servers or applications distributed to end users.
Sensitive Code Example
For debug package in Go Standard Library:
debug.PrintStack()
prints a stack trace to the standard error output (by default) which can expose sensitive information:
import "runtime/debug"
_, err := funcThatFails()
if err != nil {
fmt.Printf("Error calling funcThatFails: %v\n", err)
debug.PrintStack() // Sensitive
return
}
For pprof package in Go Standard Library:
func main() {
pprof.Lookup("goroutine").WriteTo(os.Stdout, 1) // Sensitive
}
For http/pprof package in Go Standard Library:
Importing net/http/pprof
adds several HTTP handlers that expose runtime profiling data
about the current process:
import (
"net/http"
_ "net/http/pprof" // Sensitive
)
func main() {
// Start an HTTP server that will reply (because of the importation of "net/http/pprof") to various commands
http.ListenAndServe(":6060", nil)
}
For httputil package in Go Standard Library:
httputil.DumpRequest()
generates a dump of an HTTP request and can expose sensitive information:
func requestHandler(w http.ResponseWriter, req *http.Request) {
dump, err := httputil.DumpRequest(req, true) // Sensitive
if err == nil {
fmt.Printf("%q", dump)
return
}
...
}
For GORM Library:
ORM libraries like GORM often allow logging SQL queries that may expose sensitive information:
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info), // Sensitive
})
if err != nil {
panic("failed to connect database")
}
db.Debug().Create(&User{Account: acccount, Password: password}) // Sensitive
Compliant Solution
For debug package in Go Standard Library:
Stack trace should not be printed in production:
_, err := funcThatFails()
if err != nil {
fmt.Printf("Error calling funcThatFails: %v\n", err)
// Compliant: Does not call debug.PrintStack()
return
}
For pprof package in Go Standard Library:
Avoid calling methods such as pprof.Profile.WriteTo
in production.
func main() {
// Compliant: Does not call pprof.Profile.WriteTo
}
For http/pprof package in Go Standard Library:
Do not import net/http/pprof
or ensure the HTTP handlers can’t be accessed by end-users.
import (
"net/http"
// Compliant: Does not import "net/http/pprof"
)
func main() {
// Start an HTTP server
http.ListenAndServe(":6060", nil)
}
For httputil package in Go Standard Library:
Avoid calling methods such as httputil.DumpRequest()
in production.
func requestHandler(w http.ResponseWriter, req *http.Request) {
// Compliant: Does not call httputil.DumpRequest
}
For GORM Library:
Configure loggers to not log debug-level information. GORM writes debug-level information when configured with the Info
logging mode.
Avoid using the DB.Debug()
method as it creates a new Session
that always logs debug-level information.
import (
"gorm.io/driver/sqlite"
"gorm.io/gorm"
)
db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
Logger: logger.Default.LogMode(logger.Warn), // Compliant
})
if err != nil {
panic("failed to connect database")
}
db.Create(&User{Account: acccount, Password: password}) // Compliant: Debug() is not called
See